Skip to main content

Render Your Chart Using RenderChart Function

Pre-conditions​

If you’ve followed the steps in the previous sections, you should have a copy of the code and be able to run it with an error on renderChart. If not, please revisit the previous lessons to get set up.

Implementing the renderChart​

In this section we will be setting up renderChart function with the chartModel context.

  1. Clear the content inside the renderChart function.
  2. Import ChartToTSEvent from ts-chart-sdk.
  3. Since we will be creating some custom options in using ChartToTSEvent.OpenContextMenu(sending post messages from chart to TS) in render with label Custom user action 1 and Download chart we need to create some function curresponding to that. Here are the snippet for that->
function getParsedEvent(evt: any) {
  return _.pick(evt.native, ["clientX", "clientY"]); // create a object with clicked position to open context menu there.
}

function downloadChartAsPNG() {
  const imageLink = document.createElement("a");
  const canvas = document.getElementById("chart") as any;
  imageLink.download = "bar-chart.png";
  imageLink.href = canvas.toDataURL("image/png", 1);
  imageLink.click();
} // that will be there in onClick.
  • Note:
    • For more info on CharttoTSEvent refer doc.
  1. Create a render(ctx:CustomChartContext) function which will deal with chart.js setup and using dataModel.Do the following steps to create a render function.
function render(ctx: CustomChartContext) {
  const chartModel = ctx.getChartModel();
  const dataModel = getDataModel(chartModel);
  const allowLabels = _.get(chartModel.visualProps, visualPropKeyMap[2], false);
  const labelColor = _.get(
    chartModel.visualProps,
    visualPropKeyMap[1],
    availableColor[0]
  );
  if (!dataModel) {
    return;
  }

  try {
    const canvas = document.getElementById("chart") as any;
    // clear canvas.
    canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);

    globalChartReference = new Chart(canvas as any, {
      type: "bar",
      data: {
        labels: dataModel.getLabels(),
        datasets: dataModel.getDatasets() as any,
      },
      options: {
        animation: {
          duration: 0,
        },
        scales: dataModel.getScales(),
        plugins: {
          // Change options for ALL labels of THIS CHART
          datalabels: {
            display: allowLabels,
            color: labelColor,
            labels: {
              title: {
                font: {
                  weight: "bold",
                },
              },
              value: {
                color: "black",
              },
            },
          },
        },
        // responsive: true,
        maintainAspectRatio: false,
        interaction: {
          mode: "point",
          intersect: true,
        },
        onClick: (e: any) => {
          const activeElement = e.chart.getActiveElements()[0];
          const dataX = activeElement.index;
          const dataY = activeElement.datasetIndex;

          ctx.emitEvent(ChartToTSEvent.OpenContextMenu, {
            event: getParsedEvent(e),
            clickedPoint: {
              tuple: dataModel.getPointDetails(dataX, dataY),
            },
            customActions: [
              {
                id: "custom-action-1",
                label: "Custom user action 1",
                icon: "",
                onClick: (...arg) => {
                  console.log("custom action 1 triggered", arg);
                },
              },
              {
                id: "download-chart",
                label: "Download chart",
                icon: "",
                onClick: () => {
                  downloadChartAsPNG();
                },
              },
            ],
          });
        },
      },
      plugins: [
        createPlotlinePlugin(dataModel), // Add the custom plotline plugin
        createPlotbandPlugin(dataModel), // Add the custom plotband plugin
      ],
    });
  } catch (e) {
    console.error("renderfailed", e);
    throw e;
  }
}
  1. In renderChart we will be calling render function and integrating it some custom CharttoTSEvent that will help in notifying ThoughtSpot different rendering stages. Copy the snippet below to implement it:
tip

For more information about the ChartToTSEvents component, refer to the following documentation resources: ChartToTSEventsPayloadMap

const renderChart = async (ctx: CustomChartContext): Promise<void> => {
  try {
    ctx.emitEvent(ChartToTSEvent.RenderStart);
    render(ctx);
  } catch (e) {
    ctx.emitEvent(ChartToTSEvent.RenderError, {
      hasError: true,
      error: e,
    });
  } finally {
    ctx.emitEvent(ChartToTSEvent.RenderComplete);
  }
};